package service

import (
	"admin-api/app/dao"
	"admin-api/app/models/entity"
	"admin-api/app/models/request"
	"admin-api/app/models/response"
	"admin-api/core"
	"admin-api/utils"
	"bytes"
	"fmt"
	"gitee.com/molonglove/goboot/gin"
	"gitee.com/molonglove/goboot/gorm"
	"github.com/xuri/excelize/v2"
	"net/http"
	"net/url"
	"time"
)

var Post = new(PostService)

type PostService struct{}

// Page 分页查询
func (p *PostService) Page(param *request.PostPageRequest) (*response.PageData, *response.BusinessError) {
	var (
		list  []response.PostPageResponse
		total int64
		err   error
	)
	if err = core.DB.Namespace("post").
		DQuery("postQueryPage", param).
		DOffset(param.Page, param.Size).
		TPage(&list, &total).
		Error; err != nil {
		core.Log.Error("获取岗位数据失败, 异常信息如下：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取岗位数据失败")
	}
	return &response.PageData{
		Total: total,
		Page:  param.Page,
		Size:  param.Size,
		Data:  list,
	}, nil
}

// Create 创建岗位
func (p *PostService) Create(param *request.PostCreateRequest) *response.BusinessError {
	var (
		post  entity.Post
		now   time.Time
		err   error
		exist bool
	)
	// 检测岗位名称是否唯一
	if exist = dao.Post.VerifyNameOrCodeRepetition(param.PostName, ""); err != nil || exist {
		core.Log.Error("存在相同的岗位名称")
		return response.CustomBusinessError(response.Failed, "存在相同的岗位名称")
	}
	if exist = dao.Post.VerifyNameOrCodeRepetition("", param.PostCode); err != nil || exist {
		core.Log.Error("存在相同的岗位编码")
		return response.CustomBusinessError(response.Failed, "存在相同的岗位编码")
	}
	// 保存菜单数据
	now = time.Now()
	post = entity.Post{
		PostName:   param.PostName,
		PostCode:   param.PostCode,
		PostSort:   param.PostSort,
		CreateBy:   param.UserName,
		Status:     param.Status,
		Remark:     param.Remark,
		CreateTime: &now,
	}
	if err = core.DB.Create(&post).Error; err != nil {
		return response.CustomBusinessError(response.Failed, "创建岗位失败")
	}
	core.Log.Info("创建岗位[%d:%s]成功", post.PostId, post.PostName)
	return nil
}

// Delete 删除岗位
func (p *PostService) Delete(param *request.PostDeleteRequest, username string) *response.BusinessError {
	var (
		err   error
		exist bool
	)
	if exist = dao.UserPost.ExistPostAllocatedUser(param.Ids); exist {
		core.Log.Error("存在已经分配用户的岗位")
		return response.CustomBusinessError(response.Failed, "存在已经分配用户的岗位")
	}
	if err = core.DB.Builder().
		Delete().
		From("sys_post").
		Where(gorm.In("post_id", param.Ids)).
		DExecute().
		Error; err != nil {
		core.Log.Error("删除岗位失败：%s", err.Error())
		return response.CustomBusinessError(response.Failed, "删除岗位失败")
	}
	return nil
}

// Info 岗位信息
func (p *PostService) Info(postId int64) (*response.PostInfoResponse, *response.BusinessError) {
	var (
		result response.PostInfoResponse
		post   entity.Post
		err    error
	)
	if err = core.DB.Builder().
		Select().
		From("sys_post").
		Where(gorm.Eq("post_id", postId)).
		QExecute(&post).
		Error; err != nil {
		core.Log.Error("获取岗位信息失败:%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "当前岗位不存在")
	}
	_ = utils.StructCopy(post, &result)
	return &result, nil
}

// Update 岗位更新
func (p *PostService) Update(param *request.PostUpdateRequest) *response.BusinessError {
	var (
		old       entity.Post
		now       time.Time
		condition *gorm.DB
		err       error
		exist     bool
	)
	// 检测岗位名称是否唯一
	condition = core.DB.Where("post_name = ? and post_id != ?", param.PostName, param.PostId)
	if exist, err = dao.Post.Exist(condition); err != nil || exist {
		core.Log.Error("存在相同的岗位名称")
		return response.CustomBusinessError(response.Failed, "存在相同的岗位名称")
	}
	// 检测岗位编码是否唯一
	condition = core.DB.Where("post_code = ? and post_id != ?", param.PostCode, param.PostId)
	if exist, err = dao.Post.Exist(condition); err != nil || exist {
		core.Log.Error("存在相同的岗位编码")
		return response.CustomBusinessError(response.Failed, "存在相同的岗位编码")
	}
	if old, err = dao.Post.GetById(param.PostId); err != nil {
		core.Log.Error("当前岗位不存在：%s", err.Error())
		return response.CustomBusinessError(response.Failed, "当前岗位不存在")
	}
	// 保存部门数据
	now = time.Now()
	old.PostName = param.PostName
	old.PostCode = param.PostCode
	old.PostSort = param.PostSort
	old.Status = param.Status
	old.Remark = param.Remark
	old.UpdateBy = param.UserName
	old.UpdateTime = &now
	if err = core.DB.Transaction(func(tx *gorm.DB) error {
		return dao.Post.UpdateById(tx, &old)
	}); err != nil {
		core.Log.Error("更新部门[%d]:%s", param.PostId, err.Error())
		return response.CustomBusinessError(response.Failed, "更新岗位失败")
	}
	return nil
}

// All 获取全部岗位
func (p *PostService) All() (list []response.PostListResponse, customErr *response.BusinessError) {
	var (
		result []response.PostListResponse
		err    error
	)
	if err = core.DB.Builder().
		Select(
			gorm.Field("post_id"),
			gorm.Field("post_name"),
		).
		From("sys_post").
		QExecute(&result).
		Error; err != nil {
		return nil, response.CustomBusinessError(response.Failed, "获取岗位失败")
	}
	return result, nil
}

func (p *PostService) ExportPost(ctx *gin.Context) {
	var (
		sheetName = "岗位列表"
		fileName  string
		excel     *excelize.File
		posts     []entity.Post
		buffer    bytes.Buffer
		content   *bytes.Reader
		err       error
	)
	excel = excelize.NewFile()
	defer func() {
		_ = excel.Close()
	}()
	// 将Sheet1改为自己想要的名字
	_ = excel.SetSheetName("Sheet1", sheetName)
	// 设置列宽度
	_ = excel.SetColWidth(sheetName, "A", "E", 25)
	// 设置表头
	_ = excel.SetCellValue(sheetName, "A1", "岗位名称")
	_ = excel.SetCellValue(sheetName, "B1", "岗位编码")
	_ = excel.SetCellValue(sheetName, "C1", "岗位排序")
	_ = excel.SetCellValue(sheetName, "D1", "岗位描述")
	_ = excel.SetCellValue(sheetName, "E1", "岗位状态")
	// 设置表头样式
	styleId, _ := excel.NewStyle(&excelize.Style{
		Alignment: &excelize.Alignment{Horizontal: "center"},
		Font:      &excelize.Font{Size: 16, Color: "F44022"},
	})
	_ = excel.SetRowStyle(sheetName, 1, 1, styleId)
	// 写表内容
	if posts, err = dao.Post.List(core.DB); err != nil {
		ctx.JSON(http.StatusInternalServerError, response.Fail(err.Error()))
		return
	}
	for index, post := range posts {
		_ = excel.SetCellValue(sheetName, fmt.Sprintf("A%d", index+2), post.PostName)
		_ = excel.SetCellValue(sheetName, fmt.Sprintf("B%d", index+2), post.PostCode)
		_ = excel.SetCellValue(sheetName, fmt.Sprintf("C%d", index+2), post.PostSort)
		_ = excel.SetCellValue(sheetName, fmt.Sprintf("D%d", index+2), post.Remark)
		_ = excel.SetCellValue(sheetName, fmt.Sprintf("E%d", index+2), post.Status)
	}
	// 分装excel
	if err = excel.Write(&buffer); err != nil {
		ctx.JSON(http.StatusInternalServerError, response.Fail(err.Error()))
		return
	}
	content = bytes.NewReader(buffer.Bytes())
	fileName = url.QueryEscape(fmt.Sprintf("%s.xlsx", sheetName))
	ctx.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment;filename=%s", fileName))
	ctx.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	http.ServeContent(ctx.Writer, ctx.Request, fileName, time.Now(), content)
}

// ChangeStatus 修改岗位状态
func (p *PostService) ChangeStatus(postId int64, status int, userName string) *response.BusinessError {
	if err := core.DB.Builder().
		Update().
		Table("sys_post").
		Set(
			gorm.SetField("status", status),
			gorm.SetField("update_by", userName),
			gorm.SetField("update_time", time.Now()),
		).
		Where(gorm.Eq("post_id", postId)).
		UExecute().
		Error; err != nil {
		core.Log.Error("获取岗位失败: %s", err.Error())
		return response.CustomBusinessError(response.Failed, "获取岗位失败")
	}
	return nil
}
